package com.loren.tetris.service;

import com.loren.tetris.data.GameData;
import com.loren.tetris.data.constant.DataConstant;
import com.loren.tetris.data.entity.Block;
import com.loren.tetris.data.entity.BlockShape;
import com.loren.tetris.utils.AssistiveUtils;
import com.loren.tetris.windows.GameOverFrame;
import com.loren.tetris.windows.GamePanel;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class GameService extends KeyAdapter {

    private final GamePanel gamePanel;

    private final GameOverFrame gameOverFrame;

    private final GameData gameData;

    /**
     * 是否快速下落的标记
     */
    private boolean quickDown;

    public GameService(GamePanel gamePanel, GameData gameData) {
        this.gamePanel = gamePanel;
        this.gameData = gameData;
        this.gameOverFrame = new GameOverFrame(this);
        this.startGameAboutThread();
    }

    /**
     * 键盘按键按下事件
     */
    @Override
    public void keyPressed(KeyEvent e) {
        if (this.gameData.isGamePause()) { // 如果游戏暂停，则只有Enter键能按
            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                this.gameData.setGamePause(!this.gameData.isGamePause());
            }
            return;
        }

        if (e.getKeyCode() == KeyEvent.VK_UP) { // 旋转
            this.doBlockShapeRotate();
        } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { // 向下
            this.doBlockShapeDown();
        } else if (e.getKeyCode() == KeyEvent.VK_LEFT) { // 向左
            this.doBlockShapeLeft();
        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) { // 向右
            this.doBlockShapeRight();
        } else if (e.getKeyCode() == KeyEvent.VK_CONTROL) { // 速落
            this.quickDown = true;
            while (this.quickDown) {
                this.doBlockShapeDown();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { // 暂停
            this.gameData.setGamePause(!this.gameData.isGamePause());
        } else if (e.getKeyCode() == KeyEvent.VK_SPACE) { // 阴影
            this.gameData.setEnableShadow(!this.gameData.isEnableShadow());
        }

        this.gamePanel.repaint();
    }

    /**
     * 方块旋转业务
     */
    private synchronized void doBlockShapeRotate() {
        BlockShape current = this.gameData.getCurrent();
        BlockShape tempBlockShape = current.copyBlockShape();
        tempBlockShape.blockShapeRotate();
        if (this.canBlockShapeStateExist(tempBlockShape)) {
            this.clearBlockShapeInGameMap();
            current.blockShapeRotate();
            this.freshBlockShapeInGameMap();
        }
    }

    /**
     * 方块向下业务
     */
    private synchronized void doBlockShapeDown() {
        boolean blockShapeMove = this.moveBlockShapeInGameMap(0, 1);
        if (!blockShapeMove) {
            this.quickDown = false;
            boolean frozen = this.frozenBlockShapeInGameMap();
            if (frozen) {
                int removeLineCount = this.removeLine();
                this.doGameStatistics(removeLineCount);
                this.gameData.setCurrent(this.gameData.getNext());
                this.gameData.setNext(BlockShape.blockShapeRandom());
            } else {
                this.gameData.setGameOver(true);
                this.gamePanel.removeKeyListener(this);
                this.gameOverFrame.show(this.gameData.getGameScore());
            }
        }
    }

    /**
     * 方块向左业务
     */
    private synchronized void doBlockShapeLeft() {
        this.moveBlockShapeInGameMap(-1, 0);
    }

    /**
     * 方块向右业务
     */
    private synchronized void doBlockShapeRight() {
        this.moveBlockShapeInGameMap(1, 0);
    }

    /**
     * 移动游戏地图里的方块
     */
    private boolean moveBlockShapeInGameMap(int moveX, int moveY) {
        BlockShape current = this.gameData.getCurrent();
        BlockShape tempBlockShape = current.copyBlockShape();
        tempBlockShape.blockShapeMove(moveX, moveY);
        if (this.canBlockShapeStateExist(tempBlockShape)) {
            this.clearBlockShapeInGameMap();
            current.blockShapeMove(moveX, moveY);
            this.freshBlockShapeInGameMap();
            return true;
        }
        return false;
    }

    /**
     * 将原来的位置从地图上清除
     */
    private void clearBlockShapeInGameMap() {
        BlockShape current = this.gameData.getCurrent();
        Block[][] gameMap = this.gameData.getGameMap();
        for (Block block : current.getBlockList()) {
            if (this.isCoordinateInGameMap(block.getX(), block.getY())) {
                gameMap[block.getX()][block.getY()] = null;
            }
        }
    }

    /**
     * 将方块重新刷新到地图
     */
    private void freshBlockShapeInGameMap() {
        BlockShape current = this.gameData.getCurrent();
        Block[][] gameMap = this.gameData.getGameMap();
        for (Block block : current.getBlockList()) {
            if (this.isCoordinateInGameMap(block.getX(), block.getY())) {
                gameMap[block.getX()][block.getY()] = block;
            }
        }
    }

    /**
     * 判断坐标是否在游戏地图里
     */
    private boolean isCoordinateInGameMap(int blockX, int blockY) {
        return blockX >= 0 && blockX < this.gameData.getGameMap().length && blockY >= 0 && blockY < this.gameData.getGameMap()[0].length;
    }

    /**
     * 判断方块的状态是否可以存着在地图里
     * 1、移动过后是否越过游戏边界、是否与冻结方块重叠
     * 2、旋转过后是否越过游戏边界、是否与冻结方块重叠
     */
    private boolean canBlockShapeStateExist(BlockShape blockShape) {
        return this.isInGameMap(blockShape) && this.isNoOverlapFrozenBlockShape(blockShape);
    }

    /**
     * 判断方块是否在游戏地图里
     */
    private boolean isInGameMap(BlockShape blockShape) {
        for (Block block : blockShape.getBlockList()) {
            if (block.getX() < 0 || block.getX() >= this.gameData.getGameMap().length
                    || block.getY() >= this.gameData.getGameMap()[0].length) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断方块是否不与冻结方块重叠
     */
    private boolean isNoOverlapFrozenBlockShape(BlockShape blockShape) {
        for (Block block : blockShape.getBlockList()) {
            if (this.isCoordinateInGameMap(block.getX(), block.getY())
                    && this.gameData.getGameMap()[block.getX()][block.getY()] != null
                    && this.gameData.getGameMap()[block.getX()][block.getY()].isFrozen()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 冻结方块
     */
    private boolean frozenBlockShapeInGameMap() {
        for (Block block : this.gameData.getCurrent().getBlockList()) {
            if (block.getY() < 0) {
                return false;
            }
            Block frozenBlock = Block.blockFrozen(block.getX(), block.getY());
            this.gameData.getGameMap()[block.getX()][block.getY()] = frozenBlock;
        }
        return true;
    }

    /**
     * 消行
     */
    private int removeLine() {
        Block[][] gameMap = this.gameData.getGameMap();
        // 存储需要消除行的Y坐标
        List<Integer> removeYList = new ArrayList<>();
        for (int y = 0; y < gameMap[0].length; y++) {
            boolean remove = true;
            for (Block[] blocks : gameMap) {
                if (blocks[y] == null || !blocks[y].isFrozen()) {
                    remove = false;
                    break;
                }
            }
            if (remove) {
                removeYList.add(y);
            }
        }
        int removeLineCount = removeYList.size();
        if (removeLineCount > 0) {
            if (DataConstant.ENABLE_TWINKLE) { // 消行闪烁
                this.removeLineTwinkle(gameMap, removeYList);
            }
            for (Integer count : removeYList) {
                for (int y = count; y >= 0; y--) {
                    for (int x = 0; x < gameMap.length; x++) {
                        if (y - 1 >= 0) {
                            gameMap[x][y] = gameMap[x][y - 1];
                        } else {
                            gameMap[x][y] = null;
                        }
                    }
                }
            }
        }
        return removeLineCount;
    }

    /**
     * 游戏统计（分数、消行，下一级，本地记录）
     */
    private void doGameStatistics(int removeLineCount) {
        if (removeLineCount == 0) {
            return;
        }
        int originalRemoveCount = this.gameData.getGameRemoveCount();
        int originalScore = this.gameData.getGameScore();
        this.gameData.setGameRemoveCount(originalRemoveCount + removeLineCount);
        this.gameData.setGameScore(originalScore + DataConstant.GAME_SCORE_LADDER[removeLineCount - 1]);
        if (this.gameData.getGameScore() > AssistiveUtils.getNextGameGradeScore(this.gameData.getGameGrade())) {
            this.gameData.setGameGrade(this.gameData.getGameGrade() + 1);
        }
    }

    /**
     * 开始游戏相关的线程
     */
    private void startGameAboutThread() {
        // 开始方块下落的线程
        new Thread(() -> {
            while (!this.gameData.isGameOver()) {
                if (!this.gameData.isGamePause()) {
                    this.doBlockShapeDown();
                    this.gamePanel.repaint();
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(AssistiveUtils.getBlockShapeDownSpeed(this.gameData.getGameTimeMinute()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // 开始游戏时间线程
        new Thread(() -> {
            while (!this.gameData.isGameOver()) {
                if (!this.gameData.isGamePause()) {
                    this.startGameTime();
                    this.gamePanel.repaint();
                }
                try {
                    TimeUnit.SECONDS.sleep(1L);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 游戏计时
     */
    private void startGameTime() {
        if (this.gameData.getGameTimeSecond() >= 60) {
            this.gameData.setGameTimeSecond(0);
            this.gameData.setGameTimeMinute(this.gameData.getGameTimeMinute() + 1);
        } else {
            this.gameData.setGameTimeSecond(this.gameData.getGameTimeSecond() + 1);
        }

        if (this.gameData.getGameTimeMinute() >= 60) {
            this.gameData.setGameTimeMinute(0);
            this.gameData.setGameTimeHour(this.gameData.getGameTimeHour() + 1);
        }
    }

    /**
     * 消行闪烁
     */
    private void removeLineTwinkle(Block[][] gameMap, List<Integer> removeYList) {
        for (int count = 0; count < DataConstant.REMOVE_LINE_TWINKLE_COUNT; count++) { // 使要消除的行闪烁
            for (int y : removeYList) {
                for (int x = 0; x < gameMap.length; x++) {
                    gameMap[x][y] = (count % 2 == 0) ? null : Block.blockFrozen(x, y);
                }
            }
            // repaint不会立即重绘，有个延时的过程，所以要用paintImmediately立即重绘
            this.gamePanel.paintImmediately(0, 0, this.gamePanel.getWidth(), this.gamePanel.getHeight());
            try {
                TimeUnit.MILLISECONDS.sleep(DataConstant.REMOVE_LINE_TWINKLE_TIME);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 保存本地记录
     */
    public void saveDiskRecord(String name) {
        this.gameData.saveDiskRecordList(name);
        this.gamePanel.getBtnGameStart().setEnabled(true);
        this.gamePanel.repaint();
    }
}
